import * as cheerio from 'cheerio';
import * as fs from 'fs';
import { JSDOM } from 'jsdom'
import Decimal from 'decimal.js';

const today = new Date();
export const fileName = `${today.getFullYear()}${String(today.getMonth() + 1).padStart(2, '0')}${String(today.getDate()).padStart(2, '0')}`;
// export const fileName = '20250305'

export function parseStockData (html) {
  const $ = cheerio.load(html);
  const results = [];

  // 列标题定义（根据实际HTML结构调整）
  // const headers = [
  //     '序号', 'checkbox', '股票代码', '股票简称', '现价', '涨跌幅', '成交量环比增长',
  //     '涨跌幅前复权', '涨跌', '振幅', '成交额', '注册地址', '经营范围', '首次涨停时间',
  //     '最终涨停时间', '涨停明细数据', '涨停开板次数', '阳包阴条件说明', '长下影线条件说明',
  //     '主力资金流向', '上市板块', '连续涨停天数', '涨停'
  // ];

  const headers = ['序号', 'checkbox', '股票代码', '股票简称',];

  $('.iwc-table-header-ul').find('li').each((i, li) => {
    const title = $(li).find('.thead-span.thead-span-0').text().trim()
    const sub_title = $(li).find('.thead-span.thead-span-0').siblings('.thead-sub-box')
    if (sub_title.length > 0) {
      sub_title.find('.sub-thead').each((i, ele) => {
        const day = ['3日', '5日', '10日']
        headers.push(title + day[i])
      })
    } else {
      headers.push(title)
    }
  })


  // 定位主数据表格
  $('.iwc-table-body table tbody tr').each((i, row) => {
    const cells = $(row).find('td').map((j, td) => {
      // 处理特殊内容（如超链接文本）
      const link = $(td).find('a.clickTrace');
      return link.length > 0 ? link.text().trim() : $(td).text().trim();
    }).get();

    // 排除空行（根据序号列判断）
    if (cells.length < 4 || !cells[0].match(/^\d+$/)) return;

    // 构建数据对象
    const stock = {};
    headers.forEach((key, index) => {
      if (cells[index]) stock[key] = cells[index]
    });

    // 补充固定列数据（股票代码/简称）
    const fixedCells = $(row).closest('.iwc-table-body-outer')
      .siblings('.iwc-table-header').find('th')
      .map((i, th) => $(th).text().trim()).get();

    if (fixedCells.length >= 4) {
      stock['股票代码'] = cells[2];
      stock['股票简称'] = cells[3];
    }

    results.push(stock);
  });

  return results;
}

export function cleanHTMLAttributess (tableHTML) {
  const dom = new JSDOM(tableHTML)

  const document = dom.window.document

  document.querySelectorAll('*').forEach(element => {
    Array.from(element.attributes).forEach(attr => {
      if (attr.name.startsWith('data-v-')) {
        element.removeAttribute(attr.name)
      }
    })
  })

  return dom.serialize()
}

/**判断某dom元素上是否有 xxx class */
export async function hasClass (elementHandle, className) {
  return await elementHandle.evaluate((el, className) => {
    return el.classList.contains(className)
  }, className)
}

export function saveStock (list) {
  const filePath = `./stock/${fileName}.txt`
  const stockData = JSON.stringify(list, null, 2)
  fs.writeFileSync(filePath, stockData, { encoding: 'utf-8' });
  const { modifiedJsonString, map } = extractFieldAndUnit(transformString(stockData))
  fs.writeFileSync('./stock/unit.json', JSON.stringify(map));
  fs.writeFileSync(`./stock/${fileName}.transform.json`, modifiedJsonString);
}


export async function getIndustryData (Cookie) {
  const res = {
    '热门概念': [],
    '行业': [],
    '热点新闻': [],
  }

  const hotTopic = await fetch('https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/topic?page=1&page_size=30', {
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
      Cookie
    }
  })
  if (hotTopic.ok) {
    const hotTopicData = await hotTopic.json()
    res['热点新闻'] = hotTopicData.data.topic_list.map(item => ({ title: item.title, description: item.description, hot: item.hot_value }))
  }

  const popularConcepts = await fetch('https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/plate?type=concept', {
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
      Cookie
    }
  })

  if (popularConcepts.ok) {
    const popularConceptsData = await popularConcepts.json()
    res['热门概念'] = popularConceptsData.data.plate_list.map(item => ({ name: item.name, tag: item.tag, hot_tag: item.hot_tag, '涨跌幅(%)': forceTwoDecimals(item?.rise_and_fall ?? 0) }))
  }


  const industry = await fetch('https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/plate?type=industry', {
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
      Cookie
    }
  })

  if (industry.ok) {
    const industryData = await industry.json()
    res['行业'] = industryData.data.plate_list.map(item => ({ name: item.name, tag: item.tag, hot_tag: item.hot_tag, '涨跌幅(%)': forceTwoDecimals(item?.rise_and_fall ?? 0) }))
  }

  return res
}

export function extractMarketSentiment (json) {
  const marketSentiment = {};

  // 提取情绪温度
  const txtComponents = json.data.answer[0].txt[0].content.components;
  const sentimentTxt = txtComponents.find(comp => comp.show_type = 'txt1');

  if (sentimentTxt) {
    const content = sentimentTxt.data.content;
    const currentTempMatch = content.match(/当前A股市场情绪温度为([\d.]+)度/);
    const changeMatch = content.match(/比上一个交易日变化([-]?[\d.]+)度/);
    const rangeMatch = content.match(/处于【(.*?)】/);
    if (currentTempMatch && changeMatch && rangeMatch) {
      marketSentiment["情绪温度"] = {
        "当前": currentTempMatch[1],
        "比上一个交易日变化": changeMatch[1],
        "区间": rangeMatch[1]
      };
    }
  }


  // 提取涨停数据
  const newCard = txtComponents.find(comp => comp.show_type === 'newCard');
  if (newCard) {
    const datas = newCard.data.datas;
    marketSentiment["涨停数据"] = {
      "涨停家数": datas[0]["涨停家数"],
      "跌停家数": datas[0]["跌停家数"],
      "涨跌停比": datas[0]["今日百分"],
      "昨日涨停表现": datas[1]["今日百分"],
      "连板率": datas[2]["今日百分"],
      "封板率": datas[3]["今日百分"],
      "连板收益率": {
        "今日": datas[4]["今日百分"],
        "昨日": datas[4]["昨日百分"]
      },
      "连板溢价率": {
        "今日": datas[5]["今日百分"],
        "昨日": datas[5]["昨日百分"]
      }
    };
  }


  // 提取连板天梯
  const tabTools = txtComponents.find(comp => comp.show_type === 'tab4');
  const altitude = []
  if (tabTools) {
    const tabList = tabTools.tab_list;
    // marketSentiment["连板天梯"] = {};
    const data = {
      "连板天梯": {}
    }
    tabList.forEach(tab => {
      const tabName = tab.tab_name;
      const stocks = tab.list[0].data.datas.map(stock => ({
        "代码": stock["股票代码"],
        "名称": stock["股票简称"],
        "连续涨停(天)": stock["连涨天数"],
        "成交额": stock["成交额"],
        "总市值": stock["总市值"],
        "行业": stock["所属同花顺行业"],
        "涨停原因": stock["涨停原因"]
      }));
      data["连板天梯"][tabName] = stocks;
    });
    altitude.push(...data["连板天梯"]['高位板'])
  }

  // 提取焦点股
  const focusStocksTable = txtComponents.find(comp => comp.show_type === 'tableV1');
  if (focusStocksTable) {
    const focusStocks = focusStocksTable.data.datas.map(stock => {

      const reason = altitude.find(ele => ele['代码'] === stock['股票代码'])?.['涨停原因']
      return {
        "代码": stock["股票代码"],
        "名称": stock["股票简称"],
        "连续涨停(天)": stock["连涨天数"],
        "成交额": stock["成交额"],
        "总市值": stock["总市值"],
        '涨停原因': reason,
        "行业": stock["所属同花顺行业"]
        // "涨跌幅": stock["涨跌幅:前复权"],
        // "净利润": stock["净利润"],
        // "本月涨幅": stock["本月涨幅"],
      }
    });
    marketSentiment["市场焦点股:涨停不可买入"] = focusStocks;
  }

  // 提取情绪温度走势
  // const lineChart = txtComponents.find(comp => comp.show_type === 'line3');
  // if (lineChart) {
  //   const sentimentTrend = lineChart.data.datas.map(data => ({
  //     "日期": data["时间区间"],
  //     "温度": data["情绪温度走势"].toFixed()
  //   }));
  //   marketSentiment["情绪温度走势"] = sentimentTrend;
  // }

  return marketSentiment;
}

function formatBigNumber (numStr, decimalPlaces = 2) {
  // if (typeof num !== 'number' || isNaN(num)) {
  //     return '请输入有效的数字';
  // }

  let num = Number(numStr)


  // 定义单位和对应的数值
  const units = [
    { value: 100000000, name: '亿' },
    { value: 10000, name: '万' },
    { value: 1, name: '' }
  ];

  // 处理负数
  const isNegative = num < 0;
  num = Math.abs(num);

  // 遍历单位，找到合适的单位
  for (let i = 0; i < units.length; i++) {
    if (num >= units[i].value) {
      const result = num / units[i].value;
      // 使用 toFixed 保留指定小数位数，然后去除多余的0和小数点
      const formatted = Number(result.toFixed(decimalPlaces)).toString();
      return (isNegative ? '-' : '') + formatted + units[i].name;
    }
  }

  // 如果小于1，直接返回
  return (isNegative ? '-' : '') + num.toString();
}

/** 
 * 
*/
export function IntToString (arr) {

  return arr.map(ele => {
    Object.keys(ele).forEach(key => {
      if (typeof ele[key] === 'object') {
        Object.keys(ele[key]).forEach(subKey => {
          ele[key][subKey] = formatBigNumber(ele[key][subKey])
        })
      } else if (typeof ele[key] === 'number') {
        ele[key] = formatBigNumber(ele[key])
      }
    })

    return ele
  })
}

function checkNumber (str) {
  if (!str || typeof str !== 'string') return { isNumber: false, value: NaN };

  const units = { '亿': '100000000', '万': '10000' };
  let numStr = str.trim();
  let multiplier = '1';

  // 处理单位
  for (const unit in units) {
    if (numStr.endsWith(unit)) {
      numStr = numStr.slice(0, -1);
      multiplier = units[unit];
      break;
    }
  }

  // 移除千位分隔符
  numStr = numStr.replace(/[, ]/g, '');

  // 验证数字格式
  const isValid = /^-?\d*\.?\d+$/.test(numStr);
  if (!isValid) return { isNumber: false, value: NaN };

  // 使用 Decimal 计算
  const value = new Decimal(numStr).times(multiplier).toNumber();
  return { isNumber: true, value };
}

export async function* streamCompletion (response) {
  let buffer = '';

  for await (const chunk of response.data) {
    buffer += chunk.toString();
    const lines = buffer.split('\n');

    for (let i = 0; i < lines.length - 1; i++) {
      if (lines[i].startsWith('data: ')) {
        const data = lines[i].substring(6);
        if (data === '[DONE]') {
          console.log('Stream completed');
          return; // 结束生成器
        } else {
          try {
            const parsed = JSON.parse(data);
            yield parsed; // 生成解析后的数据
          } catch (e) {
            console.error('Parse error:', e);
          }
        }
      }
    }
    buffer = lines[lines.length - 1];
  }
}


export function transformString (str) {
  const jsonData = str.replace(/[【】]/g, '') // 去除所有方括号
    .replace(/;/g, ',');   // 将分号替换为逗号

  const data = JSON.parse(jsonData);
  data['股票数据'].forEach(item => {
    delete item['序号']
    Object.keys(item).forEach(key => {
      if (key === '股票代码') return
      const { isNumber, value } = checkNumber(item[key])
      if (isNumber) {
        item[key] = value
      }
    })
    const riseAndFall = item['涨跌幅(%)']
    item['涨跌幅(%)'] = {
      '当日': riseAndFall,
      '3日': item['近3日涨幅(%)'],
      '5日': item['近5日涨幅(%)'],
      '10日': item['近10日涨幅(%)'],
    }
    delete item['近3日涨幅(%)']
    delete item['近5日涨幅(%)']
    delete item['近10日涨幅(%)']

    const capitalFlow = item['主力资金流向(元)']
    item['主力资金流向(元)'] = {
      '当日': capitalFlow,
      '3日': item['主力资金流向3日(元)'],
      '5日': item['主力资金流向5日(元)'],
      '10日': item['主力资金流向10日(元)'],
    }

    delete item['主力资金流向3日(元)']
    delete item['主力资金流向5日(元)']
    delete item['主力资金流向10日(元)']

    item['均线'] = {
      '当日': item['当日均价'],
      '3日': item['3日均线'],
      '5日': item['5日均线'],
      '10日': item['10日均线'],
    }

    delete item['当日均价']
    delete item['3日均线']
    delete item['5日均线']
    delete item['10日均线']

    item['全部资金流向'] = {
      '当日': item['当日资金流向(元)'],
      '3日': item['全部资金流向3日(元)'],
      '5日': item['全部资金流向5日(元)'],
      '10日': item['全部资金流向10日(元)'],
    }

    delete item['当日资金流向(元)']
    delete item['全部资金流向3日(元)']
    delete item['全部资金流向5日(元)']
    delete item['全部资金流向10日(元)']


    item['所属概念'] = item['所属概念'].split(',').slice(0, 4).join(',')

    delete item['公司简介']
  })

  return JSON.stringify(data);
}

export function extractFieldAndUnit (jsonString) {
  const keyRegex = /"([^"]+)"\s*:/g;
  const patternRegex = /^(.+?)\((.+?)\)$/;
  const map = {};
  const replacements = [];
  let match;
  while ((match = keyRegex.exec(jsonString)) !== null) {
    const key = match[1]; // Captured key content
    const patternMatch = key.match(patternRegex);
    if (patternMatch) {
      const field = patternMatch[1]; // "xxx" part
      const unit = patternMatch[2];   // "y" part
      map[field] = unit;             // Store in map
      replacements.push({ original: key, field }); // Record for replacement
    }
  }

  let modifiedJsonString = jsonString;
  replacements.forEach(({ original, field }) => {
    const originalKey = `"${original}"`;
    const newKey = `"${field}"`;
    modifiedJsonString = modifiedJsonString.replace(originalKey, newKey);
  });

  return { map, modifiedJsonString };
}


export function forceTwoDecimals (num) {
  return Math.round((num + Number.EPSILON) * 100) / 100;
}

export function parseStringData (input) {
  // 分割字符串并过滤空值
  const parts = input.split(/\s+/).filter(p => p);

  // 定义中英文键映射关系
  const keyMap = {
    开: 'open',
    高: 'high',
    低: 'low',
    收: 'close',
    涨跌: 'change',
    涨幅: 'change_percent'
  };

  // 创建结果对象
  const result = {};

  // 处理每个键值对（跳过第一个日期字段）
  for (let i = 1; i < parts.length; i++) {
    const [key, value] = parts[i].split(':');

    if (keyMap[key]) {
      // 处理数值和百分比
      let numValue = parseFloat(value.replace('%', ''));
      result[keyMap[key]] = isNaN(numValue) ? null : numValue;
    }
  }

  return result;
}

// function getDaysDifference(date1, date2) {
//   // 将日期转换为 Date 对象
//   const d1 = new Date(date1);
//   const d2 = new Date(date2);

//   // 计算时间差（毫秒）
//   const timeDiff = Math.abs(d2 - d1);

//   // 转换为天数（1天 = 24 * 60 * 60 * 1000 毫秒）
//   const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));

//   return daysDiff;
// }
export function stockListMerge (oldStock, newStock, key) {
  const res = oldStock
  const oldMap = oldStock.map(ele => ele[key])
  newStock.forEach(ele => {

    if (oldMap.includes(ele[key])) {
      const item = res.find(item => item[key] === ele[key])
      Object.assign(item, ele)
    } else {
      res.push(ele)
    }
  })

  return res
}